#pragma once

#include "sock.hpp"
#include <functional>
#include <sys/select.h>
#include <poll.h>
#include <string>

const static int defaultFd = -1;
const static int fdNum = 4096;

typedef std::function<std::string(const std::string &)> func_t;
// using func_t = std::function<std::string(const std::string &)>;

class Server
{

public:
    Server(uint16_t port, func_t func)
        : _listenSock(-1), _port(port), _pfds(nullptr), _func(func)
    {
    }

    void Print()
    {
        std::cout << "socket: ";
        for (int i = 0; i < fdNum; i++)
        {
            if (_pfds[i].fd != defaultFd)
                std::cout << _pfds[i].fd << " ";
        }
        std::cout << std::endl;
    }

    void Recv(int pos)
    {
        // 这里没有编写读取一个完整的报文，默认

        // 1.读取
        char buf[1024];
        int n = recv(_pfds[pos].fd, buf, sizeof(buf) - 1, 0);
        if (n > 0)
        {
            buf[n] = 0;
            std::cout << "客户端：" << buf << std::endl;

            // 2.处理数据
            std::string response = _func(buf);
            // 3.做出响应  ，这里只编写了读的转接，下面的写实际可能阻塞
            send(_pfds[pos].fd, response.c_str(), response.size(), 0);
        }
        else if (n == 0)
        {
            close(_pfds[pos].fd); // 客户端退出，把为其建立的fd关闭并在数组中移除，设为非法
            logMessage(NORMAL, "客户端退出,文件描述符%d被关闭", _pfds[pos].fd);
            _pfds[pos].fd = defaultFd;
            _pfds[pos].events = 0;
            _pfds[pos].revents = 0;
        }
        else
        {
            close(_pfds[pos].fd); // 客户端退出，把为其建立的fd关闭并在数组中移除，设为非法
            logMessage(ERROR, "客户端退出, %d: %s", errno, strerror(errno));
            _pfds[pos].fd = defaultFd;
            _pfds[pos].events = 0;
            _pfds[pos].revents = 0;
        }
    }

    void Accept(int listenSock)
    {
        std::string clientIp;
        uint16_t clientPort;
        int sock = Sock::Accept(listenSock, &clientIp, &clientPort);
        // 把新的fd托管给select，只需把新的fd添加到_fdArr数组中即可
        int i = 0;
        for (; i < fdNum; i++)
        {
            if (_pfds[i].fd != defaultFd)
                continue;
            else
                break;
        }
        if (i == fdNum) // 满了
        {
            logMessage(WARNING, "服务器已经满载");
            close(sock);
        }
        else
        {
            _pfds[i].fd = sock;
            _pfds[i].events = POLLIN;
            _pfds[i].revents = 0;
        }
        Print();
    }

    void handlerReadEvent()
    {
        for (int i = 0; i < fdNum; i++) // 可能有多个fd的读就绪
        {
            if (_pfds[i].fd == defaultFd)
                continue;

            // 进入handlerFun说明有文件描述符就绪，如何确定要使用的_listenSock就绪呢？
            if (_pfds[i].revents & POLLIN) // 读就绪的fd
            {
                if (_pfds[i].fd == _listenSock) // _listenSock就绪，执行accept
                    Accept(_pfds[i].fd);        // 到此accept不会被阻塞
                else                            // 常规的读就绪，执行读取处理
                    Recv(i);
            }
            else
            {
            }
        }
    }

    void initServer()
    {
        _pfds = new struct pollfd[fdNum];
        for (int i = 0; i < fdNum; i++)
        {
            _pfds[i].fd = defaultFd;
            _pfds[i].events = 0;
            _pfds[i].revents = 0;
        }
        _listenSock = Sock::Socket();
        Sock::Bind(_listenSock, _port);
        Sock::Listen(_listenSock);
        _pfds[0].fd = _listenSock;
        _pfds[0].events = POLLIN; // 本代码只监听读事件
    }

    void start()
    {
        for (;;)
        {
            int ret = poll(_pfds, fdNum, 0);
            switch (ret)
            {
            case 0:
            {
                // 没就绪时，返回0，非阻塞下疯狂打印，干扰调试 注释掉
                //logMessage(NORMAL, "超时返回");
            }
            break;
            case -1:
            {
                logMessage(FATAL, "select失败, %d: %s", errno, strerror(errno));
            }
            break;
            default:
            {
                logMessage(NORMAL, "事件就绪请求");
                handlerReadEvent();
                // handlerWriteEvent(wfds);
            }
            break;
            }
        }
    }

    ~Server()
    {
        if(_pfds)
            delete[] _pfds;
    }

private:
    int _listenSock;
    uint16_t _port;
    struct pollfd *_pfds;
    func_t _func;
};